﻿using LS.ModelLogicHelpers;
using LS.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using WebMatrix.WebData;

namespace LS.ActionFilter
{
    public class AppAuthorizeAttribute : AuthorizeAttribute
    {
        public class AuthorizeParameter
        {
            public AuthorizeAttribute BasicAuthorizeInfo { get; set; }

        }

        public bool NeedCheckRole { get; set; }
        public string[] ValidRoles { get; set; }
        
        public bool RedirectWhenSessionExpired { get; set; }
        public string RedirectToController { get; set; }
        public string RedirectToAction { get; set; }
        protected Func<HttpContextBase, AuthorizeParameter, bool> AdditionalAuthorize { get; set; }
        //public Action<AuthorizationContext> AdditionalHandleUnauthorizedRequest { get; set; }

        public AppAuthorizeAttribute()
        {
            RedirectWhenSessionExpired = true;
            RedirectToController = "Account";
            RedirectToAction = "Login";
            AdditionalAuthorize = null;
            //AdditionalHandleUnauthorizedRequest = null;
            //AdditionalHandleUnauthorizedRequest = DefaultUnauthorizedRequestHandle;
        }

        //public void DefaultUnauthorizedRequestHandle(AuthorizationContext authContext)
        //{
        //    authContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
        //}

        private bool CheckValidRole(HttpContextBase httpContext)
        {
            if (this.ValidRoles != null && this.ValidRoles.Length > 0)
            {
                try
                {
                    var profile = System.Web.Security.Roles.GetRolesForUser();
                    var roles = System.Web.Security.Roles.GetAllRoles();
                    foreach (var validRole in this.ValidRoles)
                    {
                        if (System.Web.Security.Roles.IsUserInRole(validRole))
                            return true;
                    }
                }
                catch
                {
                    return false;
                }

                return false;
            }
            // valid for non-role to check
            return true;
        }

        private void RedirectToLogOn(AuthorizationContext filterContext)
        {
            RouteValueDictionary dictionary = new RouteValueDictionary(new
            {
                controller = RedirectToController,
                action = RedirectToAction,
                returnUrl = filterContext.HttpContext.Request.RawUrl
            });

            filterContext.Result = new RedirectToRouteResult(dictionary);
        }

        private void RedirectToUnauthorize(AuthorizationContext filterContext)
        {
            RouteValueDictionary dictionary = new RouteValueDictionary(new
            {
                controller = "Account",
                action = "Unauthorize",
                returnUrl = filterContext.HttpContext.Request.RawUrl
            });

            filterContext.Result = new RedirectToRouteResult(dictionary);
        }

        protected virtual void ProcessUnauthorizedRequest(AuthorizationContext filterContext)
        {
            //throw new UnauthorizedAccessException(CommonInner.UnauthorizedAccess);
            throw new HttpException((int)HttpStatusCode.Unauthorized, "Authenticate faied");
            //RedirectToUnauthorize(filterContext);
        }

        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            bool isAuth = base.AuthorizeCore(httpContext);

            if (isAuth)
            {
                if (!httpContext.Request.IsAuthenticated)
                {
                    isAuth = false;
                    return isAuth;
                }

                if (null != AdditionalAuthorize)
                {
                    AuthorizeParameter para = new AuthorizeParameter()
                    {
                        BasicAuthorizeInfo = this
                    };

                    isAuth = AdditionalAuthorize(httpContext, para);
                }

                if (isAuth && this.NeedCheckRole)
                {
                    isAuth = this.CheckValidRole(httpContext);
                }
            }

            return isAuth;
        }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            if (!filterContext.HttpContext.Request.IsAuthenticated)
            {
                RedirectToLogOn(filterContext);
            }
            else
            {
                ProcessUnauthorizedRequest(filterContext);
            }

            //base.HandleUnauthorizedRequest(filterContext);

            //if (AdditionalHandleUnauthorizedRequest != null)
            //    AdditionalHandleUnauthorizedRequest(filterContext);
        }

        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            HttpContext httpcontext = HttpContext.Current;

            if (httpcontext.Session != null)
            {
                if (httpcontext.Session.IsNewSession)
                {
                    String sessioncookie = httpcontext.Request.Headers["Cookie"];
                    if ((sessioncookie != null) && (sessioncookie.IndexOf("ASP.NET_SessionId") >= 0))
                    {
                        if (RedirectWhenSessionExpired)
                        {
                            // session expired, just redirect to logon page
                            RedirectToLogOn(filterContext);
                        }
                    }
                }
            }

            base.OnAuthorization(filterContext);
        }

        protected override HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext)
        {
            return base.OnCacheAuthorization(httpContext);
        }
    }
}